/**
 * 
 */
package com.nextive.interview;

import java.util.HashMap;
import java.util.Map;

import com.nextive.interview.exception.ServiceNotRegisteredException;
import com.nextive.interview.service.UserInfoService;
import com.nextive.interview.service.WeightInfoService;
import com.nextive.interview.service.impl.UserInfoServiceImpl;
import com.nextive.interview.service.impl.WeightInfoServiceImpl;

import android.app.Application;
import android.content.Context;

/**
 * This class is intended to be used as a static way to obtain the Application's 
 * context and any service.
 * @author Cesar Roman
 *
 */
public final class ApplicationManager extends Application {
	
	/**
	 * Application's context.
	 */
	private static Context appContext;
	
	/**
	 * Map containing registered services. It contains <code>Class</code> as 
	 * key and its respective instance as value.
	 */
	private static Map<Class, Object> registeredServices = new HashMap<Class, Object>();
	
	/**
	 * Override for onCreate method. It will just fetch the 
	 * application context from its parent.
	 */
	@Override
	public void onCreate() {
		
		super.onCreate();
		appContext = getApplicationContext();
		
	}
	
	/**
	 * It returns the application's context.
	 * @return application context
	 */
	public static Context getAppContext() {
		
		return appContext;
		
	}
	
	/**
	 * It fetches the service for the given Class key. If it is not 
	 * initialized already, then it initializes and puts it into the 
	 * map for later access.
	 * @param <T> generic, will be translated when this method is being called
	 * @param classIn of the service to look for
	 * @return the service
	 */
	public static <T> T fetchService(Class<T> classIn) {
		
		if (registeredServices.containsKey(classIn))
			return (T) registeredServices.get(classIn);
		else
			return registerService(classIn);
		
	}
	
	/**
	 * It initializes the service and puts it into the map.
	 * @param <T> generic, will be translated when this method is being called
	 * @param classIn of the service to look for
	 * @return the service
	 */
	private static <T> T registerService(Class<T> classIn) {
		
		if (classIn.isAssignableFrom(UserInfoService.class)) {
			
			UserInfoService userInfoService = new UserInfoServiceImpl(appContext);
			registeredServices.put(classIn, userInfoService);
			return (T) userInfoService;
			
		} else if (classIn.isAssignableFrom(WeightInfoService.class)) {
			
			WeightInfoService weightInfoService = new WeightInfoServiceImpl(appContext);
			registeredServices.put(classIn, weightInfoService);
			return (T) weightInfoService;
			
		}
		
		throw new ServiceNotRegisteredException(classIn);
		
	}

}